# https://chat.deepseek.com/a/chat/s/d5dd1901-2d81-465e-a540-7e6a435c1a8d
# https://chat.deepseek.com/a/chat/s/b0c0162c-1150-45f2-8977-4d35f5053da4
import numpy as np

def loadDataSet():
    dataMat = []; labelMat = []
    fr = open(r'D:\email\testset.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        # 修复括号不匹配错误和多余的分号
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    fr.close()  # 添加文件关闭操作
    return dataMat, labelMat

def sigmoid(inX):
    # 使用 np.exp 替代 math.exp 以支持数组运算
    return 1.0/(1 + np.exp(-inX))

def gradAscent(dataMatIn, classLabels):
    # 转换为 NumPy 矩阵
    dataMatrix = np.mat(dataMatIn)
    labelMat = np.mat(classLabels).transpose()
    #print(dataMatrix, labelMat)
    m, n = np.shape(dataMatrix)
    alpha = 0.001
    maxCycles = 500
    weights = np.ones((n, 1))
    #print(weights)
    for k in range(maxCycles):
        h = sigmoid(dataMatrix * weights)
        #print(h)
        #每次迭代目标是error变得更小
        error = (labelMat - h)
        #print(error)
        dataV=dataMatrix.transpose()
        #print(dataV)
        weights = weights + alpha * dataV * error
        #print(weights)
    return weights

import numpy as np
import random

def stocGradAscent0(dataMatrix, classLabels):
    # 转换为 NumPy 数组
    dataMatrix = np.array(dataMatrix)  # 添加这行
    classLabels = np.array(classLabels)  # 添加这行
    
    m, n = np.shape(dataMatrix)
    alpha = 0.01
    weights = np.ones(n)
    numIter = 200  # 迭代轮数
    for j in range(numIter):
        index = list(range(m))
        random.shuffle(index)  # 打乱顺序
        for i in index:
            alpha = 4/(1.0+j+i) + 0.01  # 随迭代递减
            # 使用点积代替sum(dataMatrix[i]*weights)
            h = sigmoid(np.dot(dataMatrix[i], weights))  # 更高效的方式
            error = classLabels[i] - h
            weights = weights + alpha * error * dataMatrix[i]  # 现在应该可以工作
    
    return weights

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

def plotBestFit(weights):
    # 将权重转换为 NumPy 数组
    if isinstance(weights, np.matrix):
        weights = weights.getA()
        print(weights)
    
    # 加载数据集
    dataMat, labelMat = loadDataSet()
    dataArr = np.array(dataMat)
    
    # 获取数据点数量
    n = np.shape(dataArr)[0]
    
    # 初始化不同类别的坐标列表
    xcord1 = []; ycord1 = []  # 类别1
    xcord2 = []; ycord2 = []  # 类别0
    
    # 分类存储数据点
    for i in range(n):
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i, 1])
            ycord1.append(dataArr[i, 2])
        else:
            xcord2.append(dataArr[i, 1])
            ycord2.append(dataArr[i, 2])
    
    # 创建图形
    fig = plt.figure()
    ax = fig.add_subplot(111)
    
    # 绘制散点图
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s', label='Class 1')
    ax.scatter(xcord2, ycord2, s=30, c='green', label='Class 0')
    
    # 计算并绘制决策边界线
    x = np.arange(-3.0, 3.0, 0.1)  # X1 的范围
    # 决策边界方程: w0 + w1*x + w2*y = 0 → y = (-w0 - w1*x)/w2
    y = (-weights[0] - weights[1] * x) / weights[2]
    
    ax.plot(x, y, '-b', label='Decision Boundary')
    
    # 设置坐标轴标签
    plt.xlabel('X1')
    plt.ylabel('X2')
    
    # 添加图例
    plt.legend()
    
    # 显示图形
    plt.show()

if __name__ == "__main__":
    dataMat, labelMat = loadDataSet()
    print(dataMat, labelMat)
    weights=gradAscent(dataMat,labelMat)
    weights=stocGradAscent0(dataMat,labelMat)
    print(weights)
    plotBestFit(weights)
    print(weights)